package yxy.game.pm2.bean;

import org.redisson.api.RMap;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.game.pm2.bean.currency.CurrencyGroup;
import yxy.game.pm2.bean.currency.CurrencyNotEnoughException;
import yxy.game.pm2.bean.currency.CurrencyType;
import yxy.game.pm2.bean.db.newDao.ItemDAO;
import yxy.game.pm2.bean.db.po.ItemPo;
import yxy.game.pm2.bean.module.BaseGameRedisLockBean;

import java.util.*;
import java.util.Map.Entry;

/** 背包-物品(装备、碎片、天书、玉石) */
public class Item extends BaseGameRedisLockBean {
	// bean===========================================================================
	private CurrencyType type;// 物品类型
	private int dataId;// 数据id
	private int number;// 数量

	public CurrencyType getType() {
		return type;
	}

	public void setType(CurrencyType type) {
		this.type = type;
	}

	public int getDataId() {
		return dataId;
	}

	public void setDataId(int dataId) {
		this.dataId = dataId;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}


	// redis==========================================================================

	static public String key(String playerCode, CurrencyType type) {
		return String.format("PLAYER:%s:ITEM:%d", playerCode, type.getNumber());
	}

	static private RMap<Integer, Number> touch(String key) throws RedisException {
		return RedisManager.client(redis()).getMap(key);
	}

	public static void init(String playerCode) {
		ArrayList<CurrencyType> currencyTypes = CurrencyType.getCurrencyTypeByGroup(CurrencyGroup.ITEM);
		for(CurrencyType currencyType : currencyTypes){
			all(playerCode, currencyType);
		}
	}

	public static Map<Integer, Currency> all(String playerCode, CurrencyType type) {
		Map<Integer, Currency> map = new HashMap<>();
		try {
			RMap<Integer, Number> bucket = touch(key(playerCode, type));
			//redis中没数据的时候，从数据库取数据放入redis
			if(!bucket.isExists()){
				List<ItemPo> items = ItemDAO.getList(playerCode,type);
				if(items != null && items.size() > 0) {
					for (int i = 0; i < items.size(); i++) {
						bucket.addAndGet(items.get(i).getDataId(), items.get(i).getNumber()).longValue();
					}
				}
			}

			for (Entry<Integer, Number> entry : bucket.readAllEntrySet()) {
				int key = entry.getKey();
				long value = entry.getValue().longValue();
				Currency currency = Currency.create(type, key, value);
				map.put(key, currency);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	static public Currency get(String playerCode, CurrencyType type, int dataId) throws Exception {
		RMap<Integer, Number> bucket = touch(key(playerCode, type));
		long value = 0;
		if (!bucket.isExists() || !bucket.containsKey(dataId)) {
			ItemPo itemPo = ItemDAO.getOneByDataId(playerCode, type, dataId);
			if (itemPo != null) {
				bucket.put(itemPo.getDataId(), itemPo.getNumber());
				return Currency.create(type, itemPo.getDataId(), itemPo.getNumber());
			}
			return Currency.create(type, dataId, value);

		}
		value = bucket.get(dataId).longValue();

		return Currency.create(type, dataId, value);
	}

	static public void add(String playerCode, CurrencyType type, int dataId, long number) throws RedisException {
		String lockKey = lockKey(playerCode, type);
		try {
			if (tryLock(lockKey)) {
				RMap<Integer, Number> bucket = touch(key(playerCode, type));
				bucket.addAndGet(dataId, number).longValue();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			unlock(lockKey);
		}
	}

	static public void minus(String playerCode, CurrencyType type, int dataId, long number) throws CurrencyNotEnoughException {
		String lockKey = lockKey(playerCode, type);
		try {
			if (tryLock(lockKey)) {
				RMap<Integer, Number> bucket = touch(key(playerCode, type));
				if (!bucket.isExists() || !bucket.containsKey(dataId)) {
					throw new CurrencyNotEnoughException(type, dataId);
				}
				long value = bucket.get(dataId).longValue();
				if (number > value) {
					throw new CurrencyNotEnoughException(type, dataId);
				}
				bucket.addAndGet(dataId, -number).longValue();
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new CurrencyNotEnoughException(type, dataId);
		} finally {
			unlock(lockKey);
		}
	}

	//数据归档到数据库
	public static void saveToDB(String playerCode) {
		try {
			long updateTime = System.currentTimeMillis();
			//存储
			ArrayList<CurrencyType> cts = CurrencyType.getCurrencyTypeByGroup(CurrencyGroup.ITEM);
			for(CurrencyType ct:cts){
				List<ItemPo> items = new ArrayList<>();
				RMap<Integer, Number> bucket = touch(key(playerCode, ct));

				if (bucket.isExists()) {
					for (Entry<Integer, Number> entry : bucket.readAllEntrySet()) {
						int key = entry.getKey();
						int value = (int)entry.getValue();
						ItemPo itemPo = new ItemPo();
						itemPo.setPlayerCode(playerCode);
						itemPo.setType(ct.getNumber());
						itemPo.setDataId(key);
						itemPo.setNumber(value);
						itemPo.setUpdateTime(updateTime);
						items.add(itemPo);
					}
					ItemDAO.replace(items);
					ItemDAO.deleteByType(playerCode, ct, updateTime);
				}
			}


		}catch (Exception e){
			e.printStackTrace();
		}
	}

	//从redis移走数据
	public static void removeAllFromRedis(String playerCode) {
		try {
			ArrayList<CurrencyType> cts = CurrencyType.getCurrencyTypeByGroup(CurrencyGroup.ITEM);

			for(CurrencyType ct:cts){
				touchBucket(key(playerCode, ct)).delete();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	static private String lockKey(String playerCode, CurrencyType type) {
		return String.format("lock:%s", key(playerCode, type));
	}
}
